﻿// 这段 MFC 示例源代码演示如何使用 MFC Microsoft Office Fluent 用户界面
// (“Fluent UI”)。该示例仅供参考，
// 用以补充《Microsoft 基础类参考》和
// MFC C++ 库软件随附的相关电子文档。
// 复制、使用或分发 Fluent UI 的许可条款是单独提供的。
// 若要了解有关 Fluent UI 许可计划的详细信息，请访问
// https://go.microsoft.com/fwlink/?LinkId=238214.
//
// 版权所有(C) Microsoft Corporation
// 保留所有权利。

#include "pch.h"
#include "framework.h"

#include "PropertiesWnd.h"
#include "Resource.h"
#include "MainFrm.h"
#include "MdiApp.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif






/////////////////////////////////////////////////////////////////////////////
// CResourceViewBar

CPropertiesWnd::CPropertiesWnd() noexcept
{
    m_nComboHeight = 0;
}


CPropertiesWnd::~CPropertiesWnd()
{
}




BEGIN_MESSAGE_MAP(CPropertiesWnd, CDockablePane)
    ON_WM_CREATE()
    ON_WM_SIZE()
    ON_COMMAND(ID_EXPAND_ALL, OnExpandAllProperties)
    ON_UPDATE_COMMAND_UI(ID_EXPAND_ALL, OnUpdateExpandAllProperties)
    ON_COMMAND(ID_SORTPROPERTIES, OnSortProperties)
    ON_UPDATE_COMMAND_UI(ID_SORTPROPERTIES, OnUpdateSortProperties)
    ON_COMMAND(ID_PROPERTIES1, OnProperties1)
    ON_UPDATE_COMMAND_UI(ID_PROPERTIES1, OnUpdateProperties1)
    ON_COMMAND(ID_PROPERTIES2, OnProperties2)
    ON_UPDATE_COMMAND_UI(ID_PROPERTIES2, OnUpdateProperties2)
    ON_WM_SETFOCUS()
    ON_WM_SETTINGCHANGE()
    ON_REGISTERED_MESSAGE(AFX_WM_PROPERTY_CHANGED, OnPropertyChanged)
END_MESSAGE_MAP()




/////////////////////////////////////////////////////////////////////////////
// CResourceViewBar 消息处理程序

void CPropertiesWnd::AdjustLayout()
{
    if(GetSafeHwnd() == nullptr || ( AfxGetMainWnd() != nullptr && AfxGetMainWnd()->IsIconic() ))
    {
        return;
    }

    CRect rectClient;
    GetClientRect(rectClient);

    int cyTlb = m_wndToolBar.CalcFixedLayout(FALSE, TRUE).cy;

    m_wndObjectCombo.SetWindowPos(nullptr, rectClient.left, rectClient.top, rectClient.Width(), m_nComboHeight, SWP_NOACTIVATE | SWP_NOZORDER);
    m_wndToolBar.SetWindowPos(nullptr, rectClient.left, rectClient.top + m_nComboHeight, rectClient.Width(), cyTlb, SWP_NOACTIVATE | SWP_NOZORDER);
    m_wndPropList.SetWindowPos(nullptr, rectClient.left, rectClient.top + m_nComboHeight + cyTlb, rectClient.Width(), rectClient.Height() - ( m_nComboHeight + cyTlb ), SWP_NOACTIVATE | SWP_NOZORDER);
}


int CPropertiesWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if(CDockablePane::OnCreate(lpCreateStruct) == -1)
    {
        return -1;
    }



    CRect rectDummy;
    rectDummy.SetRectEmpty();


    /*
    * Creat combobox
    */

    const DWORD dwViewStyle = WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_BORDER | CBS_SORT | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;

    if(!m_wndObjectCombo.Create(dwViewStyle, rectDummy, this, 1))
    {
        TRACE0("未能创建属性组合 \n");
        return -1;      // 未能创建
    }


    /*
    * Practice:AddString() is different InsertString();
    */
    m_wndObjectCombo.AddString(_T("应用程序"));
    m_wndObjectCombo.InsertString(1, _T("属性窗口"));
    m_wndObjectCombo.InsertString(2, _T("chpn Add property1"));
    m_wndObjectCombo.SetCurSel(0);



    /*
    * Get m_wndObjectCombo Height
    */
    CRect rectCombo;
    m_wndObjectCombo.GetClientRect(&rectCombo);
    m_nComboHeight = rectCombo.Height();



    /*
    * Creat property list
    */
    if(!m_wndPropList.Create(WS_VISIBLE | WS_CHILD, rectDummy, this, 2))
    {
        TRACE0("未能创建属性网格\n");
        return -1;      // 未能创建
    }

    InitPropList();


    /*
    * Creat tool bar
    */
    {
        // Creat  tool bar and  set parent window
        m_wndToolBar.Create(this, AFX_DEFAULT_TOOLBAR_STYLE, IDR_PROPERTIES);
        m_wndToolBar.SetOwner(this);


        // Load and Lock Toolbar
        m_wndToolBar.LoadToolBar(IDR_PROPERTIES, 0, 0, TRUE /* 已锁定*/);


        // Load Bitmap
        m_wndToolBar.CleanUpLockedImages();
        m_wndToolBar.LoadBitmap(theApp.m_bHiColorIcons ? IDB_PROPERTIES_HC : IDR_PROPERTIES, 0, 0, TRUE /* 锁定*/);
        m_wndToolBar.SetLargeIcons(TRUE);    //set large icons


        // Set PaneStyle
        m_wndToolBar.SetPaneStyle(m_wndToolBar.GetPaneStyle() | CBRS_TOOLTIPS | CBRS_FLYBY);
        m_wndToolBar.SetPaneStyle(m_wndToolBar.GetPaneStyle() & ~( CBRS_GRIPPER | CBRS_SIZE_DYNAMIC | CBRS_BORDER_TOP | CBRS_BORDER_BOTTOM | CBRS_BORDER_LEFT | CBRS_BORDER_RIGHT ));


        // Set button style
       /* m_wndToolBar.SetButtonStyle(0, TBBS_DROPDOWN | TBBS_AUTOSIZE);
        m_wndToolBar.SetButtonStyle(1, TBBS_DROPDOWN | TBBS_AUTOSIZE);
        m_wndToolBar.SetButtonStyle(2, TBBS_DROPDOWN | TBBS_AUTOSIZE);*/



        // Set Button text,tooltip...
        CString str = _T("Property tool bar");
        m_wndToolBar.SetShowTooltips(TRUE);
        m_wndToolBar.EnableTextLabels(TRUE);   //set button text show style

        str = _T("Expand properties");
        m_wndToolBar.SetButtonText(0, str);

        str = _T("Sort alphabetically");
        m_wndToolBar.SetToolBarBtnText(1, str, TRUE, TRUE);

        str = _T("Property1");
        m_wndToolBar.SetToolBarBtnText(2, str, TRUE, TRUE);

        str = _T("Property2");
        m_wndToolBar.SetToolBarBtnText(3, str, TRUE, TRUE);


        // Set command control rote way
        m_wndToolBar.SetRouteCommandsViaFrame(FALSE); //所有命令将通过此控件路由，而不是通过主框架路由   
    }


    AdjustLayout();
    return 0;
}


void CPropertiesWnd::OnSize(UINT nType, int cx, int cy)
{
    CDockablePane::OnSize(nType, cx, cy);
    AdjustLayout();
}


void CPropertiesWnd::OnExpandAllProperties()
{
    m_wndPropList.ExpandAll(TRUE);
}


void CPropertiesWnd::OnUpdateExpandAllProperties(CCmdUI *pCmdUI)
{
    pCmdUI->Enable(TRUE);
}


void CPropertiesWnd::OnSortProperties()
{
    m_wndPropList.SetAlphabeticMode(!m_wndPropList.IsAlphabeticMode());
}


void CPropertiesWnd::OnUpdateSortProperties(CCmdUI *pCmdUI)
{
    pCmdUI->SetCheck(m_wndPropList.IsAlphabeticMode());
}


void CPropertiesWnd::OnProperties1()
{
    // TODO: 在此处添加命令处理程序代码
}


void CPropertiesWnd::OnUpdateProperties1(CCmdUI * /*pCmdUI*/)
{
    // TODO: 在此处添加命令更新 UI 处理程序代码
}


void CPropertiesWnd::OnProperties2()
{
    // TODO: 在此处添加命令处理程序代码
}


void CPropertiesWnd::OnUpdateProperties2(CCmdUI * /*pCmdUI*/)
{
    // TODO: 在此处添加命令更新 UI 处理程序代码
}


void CPropertiesWnd::InitPropList()
{
    SetPropListFont();

    m_wndPropList.EnableHeaderCtrl(FALSE);                  //set enable Header Ctrl
    m_wndPropList.EnableDescriptionArea(TRUE);              //set show Desctiption area
    m_wndPropList.SetVSDotNetLook(TRUE);                    //set Show Enable Dot Net Look
    m_wndPropList.MarkModifiedProperties(TRUE, TRUE);       //set 
    m_wndPropList.AlwaysShowUserToolTip(TRUE);              //set show tootip


    /*
    * Create a Group
    */
    {
        //Creat a Title property
        CMFCPropertyGridProperty *pTitleOutLook                 = new CMFCPropertyGridProperty(_T("外观"));
        m_wndPropList.AddProperty(pTitleOutLook);


        //Creat a bool Property
        CMFCPropertyGridProperty *pBoolPropertyIfSetOutlook3D   = new CMFCPropertyGridProperty(_T("Bool"), (_variant_t)false, _T("bool 类型属性"));
        pTitleOutLook->AddSubItem(pBoolPropertyIfSetOutlook3D);


         //Creat a Int Property
        CMFCPropertyGridProperty *pIntProperty                  = new CMFCPropertyGridProperty(_T("Int"), (_variant_t)(int)5, _T("int 类型属性"));
        pTitleOutLook->AddSubItem(pIntProperty);


        //Creat a int spin Property
        CMFCPropertyGridProperty *pIntSpintProperty             = new CMFCPropertyGridProperty(_T("Int Spin"), (_variant_t)(int)(- 1), _T("int spin 类型属性"));
        pIntSpintProperty->EnableSpinControl(TRUE, -5, 5);
        pTitleOutLook->AddSubItem(pIntSpintProperty);


         //Creat a Flot Property
        CMFCPropertyGridProperty *pFlotProperty                 = new CMFCPropertyGridProperty(_T("Flot"), (_variant_t)(float)0.5, _T("flot 类型属性"));
        pTitleOutLook->AddSubItem(pFlotProperty);


        //Creat a Double Property
        CMFCPropertyGridProperty *pDoubleProperty               = new CMFCPropertyGridProperty(_T("Double"), (_variant_t)(double)0.6, _T("double 类型属性"));
        pTitleOutLook->AddSubItem(pDoubleProperty);


        //Creat a ComboBox property
        CMFCPropertyGridProperty *pComboboxProperty             = new CMFCPropertyGridProperty(_T("Combobox"), (_variant_t)_T("选项1"), _T("Combobox 类型属性"));
        pComboboxProperty->AddOption(_T("选项1"), FALSE);
        pComboboxProperty->AddOption(_T("选项2"), FALSE);
        pComboboxProperty->AddOption(_T("选项3"));
        pComboboxProperty->AddOption(_T("选项4"));
        pComboboxProperty->AllowEdit(FALSE);
        pTitleOutLook->AddSubItem(pComboboxProperty);


        //Creat Text Edit Property
        //CMFCPropertyGridProperty *pEditProperty                 = new CMFCPropertyGridProperty(_T("文本（Text Edit)"), (_variant_t)_T("请输入文本"), _T("text edit 类型属性"));
        pEditProperty                 = new CMFCPropertyGridProperty(_T("文本（Text Edit)"), (_variant_t)_T("宋体, Arial"), _T("text edit 类型属性：显示字体类型"));
        pTitleOutLook->AddSubItem(pEditProperty);


        // creat a Font Property
        {
            //Creat Font
            LOGFONT logFont;
            CFont *pFont = CFont::FromHandle((HFONT)GetStockObject(DEFAULT_GUI_FONT));
            pFont->GetLogFont(&logFont);
            _tcscpy_s(logFont.lfFaceName, _T("宋体, Arial"));

            //Creat a  CFontDialog Property
            CMFCPropertyGridFontProperty *pFontProperty          =  new CMFCPropertyGridFontProperty(_T("字体( FontDialog)"), logFont, CF_EFFECTS | CF_SCREENFONTS, _T("CFontDialog 类型属性"));
            pTitleOutLook->AddSubItem(pFontProperty);
        }


         //Creat a  CColorDialog Property 
        {
            CMFCPropertyGridColorProperty *pColorPropertyClorDlg    = new CMFCPropertyGridColorProperty(_T("颜色(CColorDialog)"), RGB(255, 0, 255), nullptr, _T("CColorDialog 类型属性"));
            pColorPropertyClorDlg->EnableAutomaticButton(_T("默认"), ::GetSysColor(COLOR_3DFACE));
            pColorPropertyClorDlg->EnableOtherButton(_T("其他..."));
            pColorPropertyClorDlg->SetColumnsNumber(5);                 //设置颜色对话框中每行颜色选项列数
            pTitleOutLook->AddSubItem(pColorPropertyClorDlg);
        }


        //Creat a File Property
        {
            //static const TCHAR szFilter[] = _T("图文件(*.ico)|*.ico|所有文件(*.*)|*.*||");
            static const TCHAR szFilter[] = _T("所有文件(*.*)|*.*||");
            CMFCPropertyGridFileProperty *pFilePropertyIcon         = new CMFCPropertyGridFileProperty(_T("文件(CFile)"), TRUE, _T(""), _T("ico"), 0, szFilter, _T("CFile 类型属性"));
            pTitleOutLook->AddSubItem(pFilePropertyIcon);
        }


        pTitleOutLook->Expand(TRUE);
    }


    /*
    * Create a Value List property
    */
    {
        //Creat a Title property
        CMFCPropertyGridProperty *pTitleDLgSet                  = new CMFCPropertyGridProperty(_T("Value List"));
        m_wndPropList.AddProperty(pTitleDLgSet);


        //Creat a Value List Property
        CMFCPropertyGridProperty *pValueListProperty            = new CMFCPropertyGridProperty(_T("Value List"), 0, TRUE);
        pValueListProperty->AllowEdit(FALSE);
        pTitleDLgSet->AddSubItem(pValueListProperty);


        //Creat Text Edit Property
        CMFCPropertyGridProperty *pEditPropertyList0            = new CMFCPropertyGridProperty(_T("List0"), (_variant_t)_T("list 0"), _T("list Item 0"));
        pValueListProperty->AddSubItem(pEditPropertyList0);


        //Creat a Int Spin Property
        CMFCPropertyGridProperty *pIntSpinPropertyList1         = new CMFCPropertyGridProperty(_T("List2"), (_variant_t)250, _T("list Item 1"));
        pIntSpinPropertyList1->EnableSpinControl(TRUE, 100, 300);
        pValueListProperty->AddSubItem(pIntSpinPropertyList1);


         //Creat a double Property
        CMFCPropertyGridProperty *pDoublePropertyList2          = new CMFCPropertyGridProperty(_T("List3"), (_variant_t)5.5, _T("list Item 2"));
        pValueListProperty->AddSubItem(pDoublePropertyList2);


        pTitleDLgSet->Expand(TRUE);
        pValueListProperty->Expand(TRUE);//Expamd() must been used after add Subitem
    }


    //Creat a Level Tree
    {
        CMFCPropertyGridProperty *pTitlePropertyLevels          = new CMFCPropertyGridProperty(_T("层次结构"));
        m_wndPropList.AddProperty(pTitlePropertyLevels);

        CMFCPropertyGridProperty *pTitlePropertyFisrtSublevel   = new CMFCPropertyGridProperty(_T("第一个子级"));
        pTitlePropertyLevels->AddSubItem(pTitlePropertyFisrtSublevel);

        CMFCPropertyGridProperty *pTitlePropertySecondSublevel  = new CMFCPropertyGridProperty(_T("第二个子级"));
        pTitlePropertyFisrtSublevel->AddSubItem(pTitlePropertySecondSublevel);


        pTitlePropertySecondSublevel->AddSubItem(new CMFCPropertyGridProperty(_T("项 1"), (_variant_t)_T("值 1"), _T("项 1")));
        pTitlePropertySecondSublevel->AddSubItem(new CMFCPropertyGridProperty(_T("项 2"), (_variant_t)_T("值 2"), _T("项 2")));
        pTitlePropertySecondSublevel->AddSubItem(new CMFCPropertyGridProperty(_T("项 3"), (_variant_t)_T("值 3"), _T("项 3")));
        pTitlePropertyLevels->Expand(TRUE);
    }
}


void CPropertiesWnd::OnSetFocus(CWnd *pOldWnd)
{
    CDockablePane::OnSetFocus(pOldWnd);
    m_wndPropList.SetFocus();
}


void CPropertiesWnd::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
{
    CDockablePane::OnSettingChange(uFlags, lpszSection);
    SetPropListFont();
}


void CPropertiesWnd::SetPropListFont()
{
    ::DeleteObject(m_fntPropList.Detach());

    LOGFONT lf;
    afxGlobalData.fontRegular.GetLogFont(&lf);

    NONCLIENTMETRICS info;
    info.cbSize = sizeof(info);

    afxGlobalData.GetNonClientMetrics(info);

    lf.lfHeight = info.lfMenuFont.lfHeight;
    lf.lfWeight = info.lfMenuFont.lfWeight;
    lf.lfItalic = info.lfMenuFont.lfItalic;

    m_fntPropList.CreateFontIndirect(&lf);

    m_wndPropList.SetFont(&m_fntPropList);
    m_wndObjectCombo.SetFont(&m_fntPropList);
}




/**
* @brief        定义属性值改变消息处理函数。
* @param[in]    lParam  :Property属性项
* @param[in]    wParam  :控件的id
* @return 
*               - 0     :表示改变属性项值后，不发送消息AFX_WM_PROPERTY_CHANGED
*               - 1     :表示改变属性项值后，发送消息AFX_WM_PROPERTY_CHANGED
*/
LRESULT CPropertiesWnd::OnPropertyChanged(WPARAM wParam, LPARAM lParam)
{
    CMFCPropertyGridProperty *pChangedPropertyItem = (CMFCPropertyGridProperty *)lParam;

    if(!pChangedPropertyItem)
    {
        return 0;
    }


    CString     strItemName      = pChangedPropertyItem->GetName();         //被改变属性项名
    COleVariant tItemNowValue    = pChangedPropertyItem->GetValue();        //改变后,当前的值
    COleVariant tItemOriginValue = pChangedPropertyItem->GetOriginalValue();//改变之前的值


    if(!strItemName.CompareNoCase(_T("Bool")))
    {
        bool bItemValue = tItemNowValue.bVal;
        if(bItemValue = TRUE )
        {
           /*注意：SetValue 参数应当与pChangedPropertyItem值类型一直
            *       如果参数不一致，则代码运行报错
            */
            COleVariant tResetValue  = tItemOriginValue;//使修改值类型与pChangedPropertyItem类型一直
            tResetValue.bVal         =  FALSE;
            pChangedPropertyItem->SetValue(tResetValue);
        }
    }


    if(!strItemName.CompareNoCase(_T("Int")))
    {
        int nItemValue = tItemNowValue.intVal;
        if(nItemValue >= 10 || nItemValue <= 0)
        {
            tItemNowValue.intVal = 5;
            pChangedPropertyItem->SetValue(tItemNowValue);
        }
    }


    if(!strItemName.CompareNoCase(_T("Float")))
    {
        float fItemValue = V_R4(&tItemNowValue);
        if(fItemValue >= 1.0 || fItemValue <= 0.4)
        {
            tItemNowValue.fltVal = 0.5f;
            pChangedPropertyItem->SetValue(tItemNowValue);
        }
    }


    if(!strItemName.CompareNoCase(_T("Double")))
    {
        double dItemValue = V_R8(&tItemNowValue);
        if(dItemValue >= 1.0 || dItemValue <= 0.4)
        {
            tItemNowValue.dblVal = 0.6;
            pChangedPropertyItem->SetValue(tItemNowValue);
        }
    }


    if(!strItemName.CompareNoCase(_T("字体( FontDialog)")))
    {
        CMFCPropertyGridFontProperty *pFontPropertyItem = dynamic_cast<CMFCPropertyGridFontProperty*>( pChangedPropertyItem );

        if(!pFontPropertyItem)
        {
            return 0;
        }


        LPLOGFONT   fontItemValue   = pFontPropertyItem->GetLogFont();
        COleVariant tRestValue      = pEditProperty->GetValue();
        tRestValue = fontItemValue->lfFaceName;                         //这里直接赋值才能运行成功
        pEditProperty->SetValue(tRestValue);
    }


    /*注意：return 0 表示改变属性项值后，不发送消息AFX_WM_PROPERTY_CHANGED
    *       return 1 表示改变属性项值后，发送消息AFX_WM_PROPERTY_CHANGED
    */
    return 0;
}